#include <U8g2lib.h>
#include <Wire.h>
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ 33, /* data=*/ 32);
#include <OneWire.h>
#include <DallasTemperature.h>
#define MIN_RPM 0
#define MAX_RPM 5000
#define POT_PIN 34  // 电位器连接的引脚
void drawLargeDial(int rpm);
void drawOptimizedTachometer(int rpm);
#define SENSOR_PIN 25  // 使用中断引脚
#define MARKS_PER_REV 2  // 旋转物体上的标记数量
volatile unsigned long pulseCount = 0;
unsigned long lastTime = 0;
float rpm = 0;
TaskHandle_t CoreTask1;                                                                                             // 声明CoreTask1任务句柄，用于在核心1上运行任务
TaskHandle_t CoreTask2;  // 声明CoreTask2任务句柄，用于在核心2上运行任务
TaskHandle_t CoreTask3;  // 声明CoreTask3任务句柄，用于在核心2上运行任务
const int buttonPin = 5;  // 按键连接的GPIO（推荐使用带内部上拉的GPIO）
const int ledPin = 14;     // LED连接的GPIO

bool ledState = false;      // 记录LED当前状态

#define ONE_WIRE_BUS 4
// 设置单总线实例
OneWire oneWire(ONE_WIRE_BUS);

// 将单总线传递给DallasTemperature库
DallasTemperature sensors(&oneWire);
float tempC;
void IRAM_ATTR sensorInterrupt() {
  pulseCount++;
}
void task1( void * parameter ){
    Wire.begin(32, 33); // SDA, SCL
  u8g2.begin();
  // 初始显示
  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_ncenB08_tr);
  u8g2.drawStr(20, 30, "转速表初始化中...");
  u8g2.sendBuffer();
    pinMode(SENSOR_PIN, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(SENSOR_PIN), sensorInterrupt, FALLING);
  delay(1000);
  while(1)
  {
    if(millis() - lastTime >= 1000) {
    noInterrupts();  // 临时关闭中断
    rpm = (pulseCount * 60.0) / MARKS_PER_REV;
    pulseCount = 0;
    interrupts();
    
    // Serial.print("转速: ");
    // Serial.print(rpm);
    // Serial.println(" RPM");
    
    lastTime = millis();
  }
  if (ledState)
  {
  drawOptimizedTachometer((rpm*8)+800);
  }
  else
  {
    drawOptimizedTachometer(0);
  }

    vTaskDelay(10 / portMAX_DELAY); 
  }
}

void task2( void * parameter )
{
  pinMode(ledPin, OUTPUT);
  pinMode(16, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP); // 启用内部上拉电阻
  digitalWrite(ledPin, LOW);       // 初始状态关闭LED
  digitalWrite(16, LOW);       // 初始状态关闭LED
  Serial.begin(115200);
  while (1)
  {
      int currentButtonState = digitalRead(buttonPin);
      if (currentButtonState==LOW)
      {
         vTaskDelay(100 / portMAX_DELAY); 
        ledState=!ledState;
        digitalWrite(ledPin, ledState); 
      } 
  bool isRpmHigh = ((rpm * 8) + 800) > 3500;
  
  // 条件2: 温度过高
  bool isTempHigh = tempC > 32;
  
  // 任一条件满足则点亮LED
  if (isRpmHigh || isTempHigh) {
    digitalWrite(16, HIGH);
  } else {
    digitalWrite(16, LOW);
  }

      
      vTaskDelay(10 / portMAX_DELAY); 
  }
  
}

void task3( void * parameter )
{
    sensors.begin();
  while (1)
  {
      Serial.print("请求温度数据...");
  sensors.requestTemperatures(); // 发送温度读取请求
  Serial.println("完成");
  
  // 读取并打印温度数据
  tempC = sensors.getTempCByIndex(0);
  
  Serial.print("温度: ");
  Serial.print(tempC);
  Serial.print(" °C | ");
  Serial.print(DallasTemperature::toFahrenheit(tempC));
  Serial.println(" °F");
  
  vTaskDelay(1000 / portMAX_DELAY); 
  }
  

}

void setup()
{
  xTaskCreatePinnedToCore(
      task1,      // 实现任务的函数名称
      "HQQX",     // 任务的任何名称，按实际功能起名
      16384,      // 分配给任务的堆栈大小，以字节为单位，先尝试一下分配16K够不够
      NULL,       // 任务输入参数，可以为NULL
      1,          // 任务优先级，3最高，0最低
      &CoreTask1, // 任务句柄，头部已定义，亦可以为NULL
      0);         // 任务运行的内核ID（0或者1）
        xTaskCreatePinnedToCore(
      task2,      // 实现任务的函数名称
      "SEND",     // 任务的任何名称，按实际功能起名
      16384,      // 分配给任务的堆栈大小，以字节为单位，先尝试一下分配64K够不够
      NULL,       // 任务输入参数，可以为NULL
      1,          // 任务优先级，3最高，0最低
      &CoreTask2, // 任务句柄，头部已定义，亦可以为NULL
      1);         // 任务运行的内核ID（0或者1）
        xTaskCreatePinnedToCore(
      task3,      // 实现任务的函数名称
      "BDHQ",     // 任务的任何名称，按实际功能起名
      16384,      // 分配给任务的堆栈大小，以字节为单位，先尝试一下分配16K够不够
      NULL,       // 任务输入参数，可以为NULL
      0,          // 任务优先级，3最高，0最低
      &CoreTask3, // 任务句柄，头部已定义，亦可以为NULL
      0);         // 任务运行的内核ID（0或者1）
}
void loop()
{
vTaskDelay(1000 / portMAX_DELAY); // 每秒执行一次，此处应为 vTaskDelay(1000 / portTICK_PERIOD_MS);
}
void drawOptimizedTachometer(int rpm) {
  u8g2.clearBuffer();
  
  // 1. 绘制大表盘 (占用屏幕主要区域)
  drawLargeDial(rpm);
  
  // 2. 在顶部显示小号速度数字
  u8g2.setFont(u8g2_font_ncenB10_tr); // 使用中等大小字体
  u8g2.setCursor(5, 15);
  u8g2.print(tempC);
  u8g2.setCursor(50, 15);
  u8g2.print(rpm);
  
  // 3. 添加警戒区指示
  if(rpm > 2500) {
    u8g2.setDrawColor(1);
    u8g2.drawBox(100, 10, 5, 5); // 右上角小红点
  }
  
  u8g2.sendBuffer();
}

void drawLargeDial(int rpm) {
  // 表盘中心坐标和半径 (放大表盘)
  int centerX = 64;
  int centerY = 50;  // 向下移动给数字留空间
  int radius = 40;   // 更大的半径
  
  // 绘制表盘外圆
  u8g2.drawCircle(centerX, centerY, radius, U8G2_DRAW_ALL);
  
  // 绘制刻度线 (更多刻度)
  for(int i = 0; i <= 16; i++) {
    float angle = map(i, 0, 16, -150, 150) * PI / 180.0;
    
    // 主刻度(每4个小刻度一个主刻度)
    int length = (i % 4 == 0) ? 8 : 4;
    
    int x1 = centerX + (radius-length) * cos(angle);
    int y1 = centerY + (radius-length) * sin(angle);
    int x2 = centerX + radius * cos(angle);
    int y2 = centerY + radius * sin(angle);
    u8g2.drawLine(x1, y1, x2, y2);
    
    // 主刻度标签(每4000转)
    if(i % 8 == 0) {
      int labelX = centerX + (radius-15) * cos(angle);
      int labelY = centerY + (radius-15) * sin(angle);
      u8g2.setFont(u8g2_font_5x7_tr);
      u8g2.setCursor(labelX-5, labelY);
      u8g2.print((i/8)*4000);
    }
  }
  
  // 绘制指针 (加粗)
  float needleAngle = map(rpm, MIN_RPM, MAX_RPM, -150, 150) * PI / 180.0;
  int needleX = centerX + (radius-5) * cos(needleAngle);
  int needleY = centerY + (radius-5) * sin(needleAngle);
  u8g2.drawLine(centerX, centerY, needleX, needleY);
  
  // 绘制指针中心点 (加大)
  u8g2.drawDisc(centerX, centerY, 3);
  
  // 添加表盘标题
  u8g2.setFont(u8g2_font_5x7_tr);
  u8g2.setCursor(centerX-15, centerY+radius+10);
  u8g2.print("ENGINE SPEED");
}